import tkinter as tk
import tkinter
from tkinter import ttk
from PIL import Image, ImageTk
from tkinter import messagebox

k1 = ""
k2 = ""
P10 = [3, 5, 2, 7, 4, 10, 1, 9, 8, 6]
P8 = [6, 3, 7, 4, 8, 5, 10, 9]
P4 = [2, 4, 3, 1]
IP_1 = [4, 1, 3, 5, 7, 2, 8, 6]
IP = [2, 6, 3, 1, 4, 8, 5, 7]
EP = [4, 1, 2, 3, 2, 3, 4, 1]
S1_box = [["01", "00", "11", "10"], ["11", "10", "01", "00"],
          ["00", "10", "01", "11"], ["11", "01", "00", "10"]]
S2_box = [["00", "01", "10", "11"], ["10", "00", "01", "11"],
          ["11", "10", "01", "00"], ["10", "01", "00", "11"]]


# 输入主密匙，获取K1,K2
def get_key(key):
    global k1
    global k2
    # print("请输入主密匙(10bit):")
    key = substitue(key, P10)  # P10
    Ls1_L = key[:5]
    Ls1_R = key[5:10]
    Ls1_L = move(Ls1_L, 1)  # LS_1
    Ls1_R = move(Ls1_R, 1)
    k1 = Ls1_L + Ls1_R
    k1 = substitue(k1, P8)  # K1
    Ls2_L = move(Ls1_L, 2)  # LS_2
    Ls2_R = move(Ls1_R, 2)
    k2 = Ls2_L + Ls2_R
    k2 = substitue(k2, P8)  # K2
    return k1, k2


# 加密
def encrypt(p, k1, k2):
    p = substitue(p, IP)  # IP置换
    L0 = p[0:4]
    R0 = p[4:8]
    f1 = F(R0, k1)
    R1 = xor(L0, f1)
    L1 = R0
    f2 = F(R1, k2)
    L2 = xor(L1, f2)
    R2 = R1
    ciphertext = L2 + R2
    return substitue(ciphertext, IP_1)


# 解密
def decrypt(c, k1, k2):
    c = substitue(c, IP)  # IP置换
    L2 = c[0:4]
    R2 = c[4:8]
    R1 = R2
    f2 = F(R2, k2)
    L1 = xor(f2, L2)
    R0 = L1
    f1 = F(L1, k1)
    L0 = xor(f1, R1)
    Plainttext = L0 + R0
    Plainttext = substitue(Plainttext, IP_1)
    return Plainttext


# 置换
def substitue(str, P):
    new_str = ""
    for i in range(len(P)):
        new_str += str[P[i] - 1]
    return new_str


# 移位
def move(string, n):
    ch = list(string)
    new_ch = [''] * len(ch)
    for i in range(len(ch)):
        a = (i - n) % len(ch)
        if a < 0:
            if n == 1:
                new_ch[len(ch) - 1] = ch[i]
            if n == 2:
                if i == 0:
                    new_ch[len(ch) - 2] = ch[i]
                else:
                    new_ch[len(ch) - 1] = ch[i]
        else:
            new_ch[a] = ch[i]
    return ''.join(new_ch)


# f函数
def F(str, key):
    str = substitue(str, EP)  # 扩位以及置换
    # print("扩位以及置换str=",str)
    str = xor(str, key)  # 异或
    # print("异或str=",str)
    S1 = str[0:4]  # S1,S2
    S2 = str[4:8]
    S1 = searchSbox(S1, 1)  # S盒
    S2 = searchSbox(S2, 2)
    S = S1 + S2
    S = substitue(S, P4)  # P4置换
    return S


# s盒
def searchSbox(string, n):
    ret = string[0] + string[3]
    ret1 = string[1] + string[2]
    retu = ""
    if n == 1:
        retu = S1_box[int(ret, 2)][int(ret1, 2)]
    else:
        retu = S2_box[int(ret, 2)][int(ret1, 2)]
    return retu


# 异或
def xor(str, key):
    sb = []
    for i in range(len(str)):
        if str[i] == key[i]:
            sb.append("0")
        else:
            sb.append("1")
    return "".join(sb)


# 界面设计
top = tk.Tk()
top.title("S-DES encryption/decryption program")
top.geometry('700x700')


# 获取输入
def wrong():
    print('wrong')
    messagebox.showinfo('提示', '请检查输入：\n（1）明文/密文是否为8bit二进制或单个ASCII字符；\n（2）密钥是否为10bit二进制。')


def getEncrypt():
    t.configure(state=tk.NORMAL)
    p = entry.get()
    if p.isdigit():
        print("明文为数字")
    else:
        p = '{:0>8}'.format(str(bin(ord(p))[2:]))
        print("明文为字母，已转换为数字")
    key = entry1.get()
    if len(p) == 8 and all(x in "01" for x in p) and len(key) == 10 and all(x in "01" for x in key):
        print("plaintext:" + p + "\nkey:" + key)
        k1, k2 = get_key(key)
        ciphertext = encrypt(p, k1, k2)  # 加密
        print("--加密-->\nciphertext:" + ciphertext)
        t.delete('1.0', 'end')
        t.insert('1.0', ciphertext + "\n" + chr(int("0b" + ciphertext, 2)))
        t.configure(state=tk.DISABLED)
    else:
        wrong()


def getDecrtpt():
    t.configure(state=tk.NORMAL)
    ciphertext = entry.get()
    if ciphertext.isdigit():
        print("密文为数字")
    else:
        ciphertext = '{:0>8}'.format(str(bin(ord(ciphertext))[2:]))
        print("密文为字母，已转换为数字")
    key = entry1.get()
    if len(ciphertext) == 8 and all(x in "01" for x in ciphertext) and len(key) == 10 and all(x in "01" for x in key):
        print("ciphertext:" + ciphertext + "\nkey:" + key)
        k1, k2 = get_key(key)
        plaintext = decrypt(ciphertext, k1, k2)
        print("---->plaintext:" + plaintext)
        t.delete('1.0', 'end')
        t.insert('1.0', plaintext + "\n" + chr(int("0b" + plaintext, 2)))
        t.configure(state=tk.DISABLED)
    else:
        wrong()


# 输入框
tk.Label(top, text="Plaintext/Ciphertext：", font=("华文新魏", 18)).place(x=60, y=40)
entry = tk.Entry(top)
entry.place(x=60, y=100, width=550, height=60)
entry.configure(font=("华文新魏", 16))

tk.Label(top, text="Key：", font=("华文新魏", 18)).place(x=60, y=180)
entry1 = tk.Entry(top)
entry1.place(x=60, y=220, width=550, height=60)
entry1.configure(font=("华文新魏", 16))

tk.Label(top, text="Result：", font=("华文新魏", 18)).place(x=60, y=320)
t = tk.Text(top, width=45, height=3)
t.place(x=60, y=400)
t.configure(font=("华文新魏", 16))


# button
tk.Button(top, text=" encrypt ", borderwidth=0, bg="red", activeforeground="#B0C4DE", font=("华文新魏", 18),
          command=getEncrypt).place(x=140, y=550)
tk.Button(top, text=" decrypt ", borderwidth=0, bg="red", activeforeground="#B0C4DE", font=("华文新魏", 18),
          command=getDecrtpt).place(x=460, y=550)


top.mainloop()
